package juntos.lbcv.dao;

import java.util.Date;
import java.util.List;
import java.util.Set;

import juntos.lbcv.model.Alert;
import juntos.lbcv.model.AlertAnnonce;
import juntos.lbcv.model.AlertDepartement;
import juntos.lbcv.model.AlertLocalisation;
import juntos.lbcv.model.AlertMarque;
import juntos.lbcv.model.AlertModele;
import juntos.lbcv.model.AlertRegion;
import juntos.lbcv.model.Annonce;
import juntos.lbcv.model.Annonceur;
import juntos.lbcv.model.RefBoiteVitesse;
import juntos.lbcv.model.RefCarburant;
import juntos.lbcv.model.RefLocalisation;
import juntos.lbcv.model.RefModele;
import juntos.lbcv.model.RefTypeAnnonceur;
import juntos.lbcv.model.UserAlert;
import juntos.lbcv.utils.Lbc;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

@Repository("alertDAO")
public class AlertDAO extends DAO {

	@SuppressWarnings("unchecked")
	public List<Alert> findAllAlert() {
		return (List<Alert>) findAll(Alert.class);
	}

	public void persitAlertAnnonce(AlertAnnonce alertAnnonce) {
		Criteria cr = this
				.createCriteria(AlertAnnonce.class)
				.add(Restrictions.eq("alert.id", alertAnnonce.getAlert()
						.getId()))
				.add(Restrictions.eq("annonce.id", alertAnnonce.getAnnonce()
						.getId()));

		if (cr.uniqueResult() == null) {
			persist(alertAnnonce);
		}
	}

	@SuppressWarnings("unchecked")
	public List<Annonce> findAllNewAnnonce(Date datePublication) {
		return (List<Annonce>) this.createCriteria(Annonce.class)
				.add(Restrictions.ge("datePublication", datePublication))
				.add(Restrictions.eq("statut", 0)).setMaxResults(100).list();
	}

	@SuppressWarnings("unchecked")
	public List<UserAlert> findAllUserAlert() {
		return (List<UserAlert>) findAll(UserAlert.class);
	}

	@SuppressWarnings("unchecked")
	public List<AlertAnnonce> findAllAlertAnnoncesByAlertAndStatut(Alert alert) {
		Criteria cr = this.createCriteria(AlertAnnonce.class)
				.add(Restrictions.eq("alert.id", alert.getId()))
				.add(Restrictions.eq("statut", 0));
		return (List<AlertAnnonce>) cr.list();
	}

	public boolean isAnnonceLikeAlert(Annonce annonce, Alert alert) {
		if (!this.verifMarqueAndModele(alert, annonce.getRefModele()))
			return false;
		if (!this.verifTypeAnnonceur(alert, annonce.getAnnonceur()
				.getRefTypeAnnonceur()))
			return false;
		if (!this.verifCarburant(alert, annonce.getRefCarburant()))
			return false;
		if (!this.verifBoiteVitesse(alert, annonce.getRefBoiteVitesse()))
			return false;
		if (!this.verifLocalisation(alert, annonce.getRefLocalisation()))
			return false;
		if (!this.verifSearch(alert.getSearch(), annonce.getAnnonceur(),
				annonce.getTitre(), annonce.getDescription()))
			return false;
		if (!this.verifPrice(alert.getPrixMin(), alert.getPrixMax(),
				annonce.getPrix()))
			return false;
		if (!this.verifKilometrage(alert.getKilometrageMin(),
				alert.getKilometrageMax(), annonce.getKilometrage()))
			return false;
		if (!this.verifAnneModele(alert.getAnneeModeleMin(),
				alert.getAnneeModeleMax(), annonce.getAnneeModele()))
			return false;
		if (!this.verifDatePublication(alert.getDatePublicationMin(),
				alert.getDatePublicationMax(), annonce.getDatePublication()))
			return false;
		return true;
	}

	private boolean verifDatePublication(Date datePublicationMin,
			Date datePublicationMax, Date datePublication) {
		if (datePublicationMin != null
				&& datePublicationMin.compareTo(datePublication) > 0)
			return false;
		if (datePublicationMax != null
				&& datePublicationMax.compareTo(datePublication) < 0)
			return false;
		return true;
	}

	private boolean verifAnneModele(Date anneeModeleMin, Date anneeModeleMax,
			Date anneeModele) {
		if (anneeModeleMin != null && anneeModeleMin.compareTo(anneeModele) > 0)
			return false;
		if (anneeModeleMax != null && anneeModeleMax.compareTo(anneeModele) < 0)
			return false;
		return true;

	}

	private boolean verifKilometrage(long kilometrageMin, long kilometrageMax,
			long kilometrage) {
		return kilometrageMin <= kilometrage
				&& (kilometrage <= kilometrageMax || kilometrageMax == 0);
	}

	private boolean verifPrice(long prixMin, long prixMax, long prix) {
		return prixMin <= prix && (prix <= prixMax || prixMax == 0);
	}

	private boolean verifSearch(String search, Annonceur annonceur,
			String titre, String description) {
		if (search == null)
			return true;
		String s = search.toLowerCase();
		// recupération et traitement du nom
		String nom = annonceur.getNom().toLowerCase();
		String names = Lbc.subString(s, "[", "]");
		for (String n : names.split(";")) {
			if (nom.contains(n))
				return true;
		}
		// récupération et traitement du titre
		String title = titre.toLowerCase();
		String titles = Lbc.subString(s, "(", ")");
		for (String t : titles.split(";")) {
			if (title.contains(t))
				return true;
		}
		// récupération et traitement de la description
		String desc = description.toLowerCase();
		String descs = desc.replace(names, "").replace(titles, "");
		for (String d : descs.split(";")) {
			if (title.contains(d))
				return true;
		}
		return false;
	}

	private boolean verifLocalisation(Alert alert, RefLocalisation localisation) {
		Set<AlertRegion> alertRegions = alert.getAlertRegions();
		Set<AlertDepartement> alertDepartements = alert.getAlertDepartements();
		Set<AlertLocalisation> alertLocalisations = alert
				.getAlertLocalisations();

		if (alertLocalisations.isEmpty() && alertDepartements.isEmpty()
				&& alertRegions.isEmpty())
			return true;

		for (AlertLocalisation alo : alertLocalisations) {
			if (alo.getRefLocalisation().equals(localisation))
				return true;
		}

		for (AlertDepartement ade : alertDepartements) {
			if (ade.getRefDepartement()
					.equals(localisation.getRefDepartement()))
				return true;
		}

		for (AlertRegion are : alertRegions) {
			if (are.getRefRegion().equals(
					localisation.getRefDepartement().getRefRegion()))
				return true;
		}

		return false;
	}

	private boolean verifBoiteVitesse(Alert alert,
			RefBoiteVitesse refBoiteVitesse) {
		RefBoiteVitesse alertBoiteVitesse = alert.getRefBoiteVitesse();
		if (alertBoiteVitesse == null)
			return true;
		if (alertBoiteVitesse.equals(refBoiteVitesse))
			return true;
		return false;
	}

	private boolean verifCarburant(Alert alert, RefCarburant refCarburant) {
		RefCarburant alertCarburant = alert.getRefCarburant();
		if (alertCarburant == null)
			return true;
		if (alertCarburant.equals(refCarburant))
			return true;
		return false;
	}

	private boolean verifTypeAnnonceur(Alert alert,
			RefTypeAnnonceur refTypeAnnonceur) {
		RefTypeAnnonceur alertTypeAnnonceur = alert.getRefTypeAnnonceur();
		if (alertTypeAnnonceur == null)
			return true;
		if (alertTypeAnnonceur.equals(refTypeAnnonceur))
			return true;
		return false;
	}

	private boolean verifMarqueAndModele(Alert alert, RefModele refModele) {
		Set<AlertModele> alertModeles = alert.getAlertModeles();
		Set<AlertMarque> alertMarques = alert.getAlertMarques();
		// true si modele et marque vide
		if (alertModeles.isEmpty() && alertMarques.isEmpty())
			return true;
		// controle Modele
		for (AlertModele amo : alertModeles) {
			if (amo.getRefModele().equals(refModele))
				return true;
		}
		// ontrole alert
		if (alertModeles.isEmpty()) {
			for (AlertMarque amq : alertMarques) {
				if (amq.getRefMarque().equals(refModele.getRefMarque()))
					return true;
			}
		}
		return false;
	}

}